<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>事务与自动提交</title>

 </head>
 <body><div class="manualnavbar" style="text-align: center;">
 <div class="prev" style="text-align: left; float: left;"><a href="pdo.connections.html">连接与连接管理</a></div>
 <div class="next" style="text-align: right; float: right;"><a href="pdo.prepared-statements.html">预处理语句与存储过程</a></div>
 <div class="up"><a href="book.pdo.html">PDO</a></div>
 <div class="home"><a href="index.html">PHP Manual</a></div>
</div><hr /><div id="pdo.transactions" class="chapter">
 <h1>事务与自动提交</h1>

 <p class="para">
  现在通过 PDO 连接上了，在开始进行查询前，必须先理解 PDO 是如何管理事务的。事务支持四大特性（ACID）：原子性（Atomicity）、一致性（Consistency）、隔离性（Isolation）以及持久性（Durability）。通俗地讲，在一个事务中执行的任何操作，即使是分阶段执行的，也能保证安全地应用于数据库，并在提交时不会受到来自其他连接的干扰。事务操作也可以根据请求自动撤销（假设还没有提交），这使得在脚本中处理错误更加容易。
 </p>
 <p class="para">
  事务通常是通过把一批更改“积蓄”起来然后使之同时生效而实现的；这样做的好处是可以大大地提供这些更改的效率。换句话说，事务可以使脚本更快，而且可能更健壮（不过需要正确地使用事务才能获得这样的好处）。
 </p>
 <p class="para">
  不幸的是，并非每种数据库都支持事务，因此当第一次打开连接时，PDO 需要在所谓的“自动提交”模式下运行。自动提交模式意味着，如果数据库支持，运行的每个查询都有它自己的隐式事务，如果数据库不支持事务，则没有。如果需要一个事务，则必须用 <span class="function"><a href="pdo.begintransaction.html" class="function">PDO::beginTransaction()</a></span> 方法来启动。如果底层驱动不支持事务，则抛出一个 PDOException 异常（不管错误处理设置是怎样的，这都是一个严重的错误状态）。一旦开始了事务，可用 <span class="function"><a href="pdo.commit.html" class="function">PDO::commit()</a></span> 或 <span class="function"><a href="pdo.rollback.html" class="function">PDO::rollBack()</a></span>来完成，这取决于事务中的代码是否运行成功。
 </p>
 <div class="warning"><strong class="warning">Warning</strong>
  <p class="para">
   PDO 仅在驱动层检查是否具有事务处理能力。如果某些运行时条件意味着事务不可用，且数据库服务接受请求去启动一个事务，<span class="methodname"><a href="pdo.begintransaction.html" class="methodname">PDO::beginTransaction()</a></span> 将仍然返回 <strong><code>TRUE</code></strong> 而且没有错误。
  </p>
  <p class="para">
   试着在 MySQL 数据库的  MyISAM 数据表中使用事务就是一个很好的例子。
  </p>
 </div>
 <p class="para">
  当脚本结束或连接即将被关闭时，如果尚有一个未完成的事务，那么 PDO 将自动回滚该事务。这种安全措施有助于在脚本意外终止时避免出现不一致的情况——如果没有显式地提交事务，那么假设是某个地方出错了，所以执行回滚来保证数据安全。
 </p>
 <div class="warning"><strong class="warning">Warning</strong>
  <p class="para">
   只有通过 <span class="function"><a href="pdo.begintransaction.html" class="function">PDO::beginTransaction()</a></span> 启动一个事务后，才可能发生自动回滚。如果手动发出一条查询启动事务， 则 PDO 无法知晓，从而在必要时不能进行回滚。
  </p>
 </div>
 <p class="para">
  <div class="example" id="example-877"><p><strong>Example #1 在事务中执行批处理</strong></p>
   <div class="example-contents"><p>
    在下面例子中，假设为新员工创建一组条目，分配一个为23的ID。除了登记此人的基本数据之外，还需要记录他的工资。两个更新分别完成起来很简单，但通过封闭在 <span class="function"><a href="pdo.begintransaction.html" class="function">PDO::beginTransaction()</a></span> 和<span class="function"><a href="pdo.commit.html" class="function">PDO::commit()</a></span> 调用中，可以保证在更改完成之前，其他人无法看到这些更改。如果发生了错误，catch 块回滚自事务启动以来发生的所有更改，并输出一条错误信息。
   </p></div>
   <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">try&nbsp;{<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$dbh&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">PDO</span><span style="color: #007700">(</span><span style="color: #DD0000">'odbc:SAMPLE'</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'db2inst1'</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'ibmdb2'</span><span style="color: #007700">,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array(</span><span style="color: #0000BB">PDO</span><span style="color: #007700">::</span><span style="color: #0000BB">ATTR_PERSISTENT&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">true</span><span style="color: #007700">));<br />&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"Connected\n"</span><span style="color: #007700">;<br />}&nbsp;catch&nbsp;(</span><span style="color: #0000BB">Exception&nbsp;$e</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;die(</span><span style="color: #DD0000">"Unable&nbsp;to&nbsp;connect:&nbsp;"&nbsp;</span><span style="color: #007700">.&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getMessage</span><span style="color: #007700">());<br />}<br /><br />try&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$dbh</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setAttribute</span><span style="color: #007700">(</span><span style="color: #0000BB">PDO</span><span style="color: #007700">::</span><span style="color: #0000BB">ATTR_ERRMODE</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">PDO</span><span style="color: #007700">::</span><span style="color: #0000BB">ERRMODE_EXCEPTION</span><span style="color: #007700">);<br /><br />&nbsp;&nbsp;</span><span style="color: #0000BB">$dbh</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">beginTransaction</span><span style="color: #007700">();<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$dbh</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">exec</span><span style="color: #007700">(</span><span style="color: #DD0000">"insert&nbsp;into&nbsp;staff&nbsp;(id,&nbsp;first,&nbsp;last)&nbsp;values&nbsp;(23,&nbsp;'Joe',&nbsp;'Bloggs')"</span><span style="color: #007700">);<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$dbh</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">exec</span><span style="color: #007700">(</span><span style="color: #DD0000">"insert&nbsp;into&nbsp;salarychange&nbsp;(id,&nbsp;amount,&nbsp;changedate)&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;values&nbsp;(23,&nbsp;50000,&nbsp;NOW())"</span><span style="color: #007700">);<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$dbh</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">commit</span><span style="color: #007700">();<br />&nbsp;&nbsp;<br />}&nbsp;catch&nbsp;(</span><span style="color: #0000BB">Exception&nbsp;$e</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$dbh</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">rollBack</span><span style="color: #007700">();<br />&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"Failed:&nbsp;"&nbsp;</span><span style="color: #007700">.&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getMessage</span><span style="color: #007700">();<br />}<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code></div>
   </div>

  </div>
 </p>
 <p class="para">
  并不局限于在事务中更改，也可以发出复杂的查询来提取数据，还可以使用那些信息来构建更多的更改和查询；当事务激活时，可以保证其他人在操作进行当中无法作出更改。想更进一步阅读关于事务的信息，可参考数据库服务提供的文档。
 </p>
</div>
<hr /><div class="manualnavbar" style="text-align: center;">
 <div class="prev" style="text-align: left; float: left;"><a href="pdo.connections.html">连接与连接管理</a></div>
 <div class="next" style="text-align: right; float: right;"><a href="pdo.prepared-statements.html">预处理语句与存储过程</a></div>
 <div class="up"><a href="book.pdo.html">PDO</a></div>
 <div class="home"><a href="index.html">PHP Manual</a></div>
</div></body></html>
